package cn.siat.gene.service;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.IdUtil;
import cn.siat.common.core.exception.ServiceException;
import cn.siat.common.core.utils.StringUtils;
import cn.siat.gene.domain.Feature;
import cn.siat.gene.domain.Programme;
import cn.siat.gene.mapper.ProgrammeMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.io.*;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Service
@RequiredArgsConstructor
@Slf4j
public class AsyncBioinformaticsPipelineService {
    private final ProgrammeMapper programmeMapper;
    private final FeatureService featureService;

    private final String separator = File.separator;

    private String getPrefixPath() {
        String osName = System.getProperty("os.name").toLowerCase();
        String prefixPath = "";
        if (osName.contains("win")) {
            prefixPath = "D:" + separator + "gene" + separator;
        } else if (osName.contains("nix") || osName.contains("nux") || osName.contains("aix")) {
            prefixPath = separator + "opt" + separator + "big-folder" + separator + "BioinformaticsPipeline" + separator;
        } else if (osName.contains("mac")) {
            prefixPath = separator + "usr" + separator + "local" + separator;
        } else {
            throw new ServiceException("未知操作系统");
        }
        return prefixPath + "result" + separator;
    }
    @Async
    public void asyncBlast(Map<String, String> params) {
        try{
            String prefixPath = getPrefixPath();
            String chr = params.get("chr");
            String start = params.get("start");
            String end = params.get("end");
            String seq = params.get("seq");
            String number = params.get("number");
            String type = null;
            if("M0000002".equals(number)){
                type = "blast2go_source";
            }else if("M0000004".equals(number)){
                type = "blast2kegg_source";
            }else{
                throw new ServiceException("当前分析程序不存在!");
            }
            String snowId = IdUtil.getSnowflakeNextIdStr();
            String basePath = prefixPath + snowId;
            //生成config.yaml文件
            FileUtil.mkdir(basePath);
            File configYaml = FileUtil.file(basePath + separator + "config.yaml");
            PrintWriter printWriter = null;
            try {
                printWriter = new PrintWriter(configYaml);
                printWriter.println("chr: \""+chr+"\"");
                printWriter.println("start: "+start);
                printWriter.println("end: "+end);
                printWriter.println("seq: \""+seq+"\"");
                printWriter.println("idmapping: \"/opt/big-folder/BioinformaticsPipeline/DB/duckDB/idmapping.duckdb\"");
                printWriter.println("db: \"/opt/big-folder/BioinformaticsPipeline/DB/swissprot\"");
            }catch (FileNotFoundException e){
                log.error(e.getMessage());
            } finally {
                if (printWriter != null) {
                    printWriter.close();
                }
            }
            runCommand(basePath,type);

            File csv;
            if(basePath.contains("opt")){
                csv = new File(basePath + separator + "output" + separator + "annotated.csv");
//            csv = new File("/opt/big-folder/BioinformaticsPipeline/blast2kegg_source/output/annotated.csv");
            }else{
                csv = new File("D:\\gene\\annotated.csv");
            }

            //读取csv文件
            if(csv.exists()){

                BufferedReader br = null;
                try {
                    String line ;
                    StringBuffer sb = new StringBuffer();
                    br = new BufferedReader(new FileReader(csv));
                    while ((line = br.readLine()) != null) {
                        sb.append(line);
                    }
//                    Map<String,Object> map = new HashMap<>();
//                    map.put("name", sb);
//                    map.put("start", start);
//                    map.put("end", end);
//                    map.put("chr", chr);

                    Feature feature = new Feature()
                            .setName(sb.toString())
                            .setStart(Integer.valueOf(start))
                            .setEnd(Integer.valueOf(end))
                            .setSequenceId(Long.valueOf(chr));
                    System.err.println(feature);
                    featureService.saveFeatureList(CollectionUtil.newArrayList(feature));
                } catch (IOException e) {
                    log.error(e.getMessage());
                }finally {
                    if(br!=null){
                        try {
                            br.close();
                        } catch (IOException e) {
                            log.error(e.getMessage());
                        }
                    }
                    FileUtil.del(basePath );
                }
            }else{
                throw new ServiceException("无注释信息");
            }
        }catch (Exception e){
            throw e;
        }finally {
            //分析状态改为运行完毕
            programmeMapper.updateById(new Programme()
                    .setId(params.get("programmeId"))
                    .setAnalyseState(1)
                    .setProgrammeState(1));
        }
    }


    void runCommand(String path, String type) {
        File runPath = new File(path+separator+"run.sh");
        if(path.contains("opt")){
            FileUtil.copy(new File("/opt/big-folder/BioinformaticsPipeline/run.sh"), runPath, true);
        }else{
            FileUtil.copy(new File("D:\\gene\\run.sh"), runPath, true);
        }


        FileWriter  fw = null;
        try {
            fw = new FileWriter(runPath,true);
            fw.write("\n");
            fw.write("cd /opt/big-folder/BioinformaticsPipeline/"+type+"\n");
            fw.write("snakemake --cores 8 --directory "+path+"\n");
        } catch (IOException e) {
            log.error(e.getMessage());
        } finally {
            try {
                if(fw!=null){
                    fw.close();
                }
            } catch (IOException e) {
                log.error(e.getMessage());
            }
        }
        System.err.println(path);
        if(path.contains("opt")){
            String[]command= new String[]{"sh",runPath.getPath()};
            execCmdOrder(command);
        }
    }



    void execCmdOrder(String[]command) {
        System.out.println("执行命令中...");
        if (StringUtils.isEmpty(command)){
            throw new RuntimeException("需要执行的命令不可以为空");
        }

        BufferedReader br=null;
        Process process=null;
        try {
            //执行cmd命令
            System.err.println(Arrays.toString(command));
            process = Runtime.getRuntime().exec(command);

            //获取cmd命令的输出结果
            br=new BufferedReader(new InputStreamReader(process.getInputStream(), Charset.forName("GBK")));
            String tmp;
            //组装命令执行结束后返回值
            while ((tmp= br.readLine())!=null){
                log.info(tmp);
            }
            // 等待进程结束
            while (process.isAlive()) {
                process.waitFor(10L, TimeUnit.MINUTES);
            }
        } catch (InterruptedException | IOException e) {
            log.error(e.getMessage());
        }finally {
            if (br!=null){
                try {
                    br.close();
                } catch (IOException e) {
                    log.error(e.getMessage());
                }
            }
            if (process != null) {
                process.destroy();
            }
            System.out.println("执行完毕!");
        }
    }

}

